/*
 * Copyright (c) 2019  STMicroelectronics – All rights reserved
 * The STMicroelectronics corporate logo is a trademark of STMicroelectronics
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice, this list of conditions
 *   and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright notice, this list of
 *   conditions and the following disclaimer in the documentation and/or other materials provided
 *   with the distribution.
 *
 * - Neither the name nor trademarks of STMicroelectronics International N.V. nor any other
 *   STMicroelectronics company nor the names of its contributors may be used to endorse or
 *   promote products derived from this software without specific prior written permission.
 *
 * - All of the icons, pictures, logos and other images that are provided with the source code
 *   in a directory whose title begins with st_images may only be used for internal purposes and
 *   shall not be redistributed to any third party or modified in any way.
 *
 * - Any redistributions in binary form shall not include the capability to display any of the
 *   icons, pictures, logos and other images that are provided with the source code in a directory
 *   whose title begins with st_images.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 * OF SUCH DAMAGE.
 */
package com.st.BlueMS.demos.multiNN

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.st.BlueSTSDK.Feature
import com.st.BlueSTSDK.Features.FeatureActivity
import com.st.BlueSTSDK.Features.FeatureAudioClassification
import com.st.BlueSTSDK.Node

internal data class AvailableAlgorithm(
        val index:Int,
        val name:String
)

internal class MultiNNViewModelFactory(private val node: Node) : ViewModelProvider.Factory {

    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        return modelClass.getConstructor(Node::class.java).newInstance(node)
    }
}

internal class MultiNNViewModel(node: Node) : ViewModel() {

    private val mConsole:MultiNNConsole = MultiNNConsole(node.debug!!)
    private val audioNN: Feature?
    private val activityNN:Feature?

    init {
        audioNN = node.getFeature(FeatureAudioClassification::class.java)
        activityNN = node.getFeature(FeatureActivity::class.java)
    }

    private val _currentAlgorithm = MutableLiveData<AvailableAlgorithm>()
    val currentAlgorithm:LiveData<AvailableAlgorithm>
        get() = _currentAlgorithm


    private val _availableAlgorithms = MutableLiveData<List<AvailableAlgorithm>>()
    val availableAlgorithm:LiveData<List<AvailableAlgorithm>>
        get() = _availableAlgorithms

    private val _showAlgorithmList = MutableLiveData<Boolean>()
    val showAlgorithmList:LiveData<Boolean>
        get() = _showAlgorithmList

    private fun enableAIFeature(){
        audioNN?.enableNotification()
        activityNN?.enableNotification()
        audioNN?.read()
        activityNN?.read()
    }

    private fun disableAIFeature(){
        audioNN?.disableNotification()
        activityNN?.disableNotification()
    }

    fun selectAlgorithm(algorithm: AvailableAlgorithm){
        _currentAlgorithm.postValue(algorithm)
        disableAIFeature()
        mConsole.enableAlgorithm(algorithm, onAlgorithmEnabled = {
            enableAIFeature()
        })
    }

    fun loadAvailableAlgorithms(){
        if(_availableAlgorithms.value == null) {
            mConsole.getAvailableAlgorithms { algos ->
                _showAlgorithmList.postValue(!algos.isNullOrEmpty())
                _availableAlgorithms.postValue(algos)
                if(algos == null) {
                    // if only one algorithm is present enable the notification, otherwise wait the
                    // algorithm selection
                    enableAIFeature()
                }
            }
        }
    }

    fun startMultiNeuralNetwork(){
        val algo = currentAlgorithm.value
        if(algo == null){
            loadAvailableAlgorithms()
        }else{
            selectAlgorithm(algo)
        }
    }

    fun stopMultiNeuralNetwork(){
        disableAIFeature()
    }

}